package org.intellij.plugins.junit4;

import com.intellij.codeInsight.intention.IntentionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataKeys;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.PsiManager;
import com.intellij.refactoring.listeners.RefactoringListenerManager;
import org.apache.log4j.Logger;
import org.intellij.plugins.junit4.intentions.AddTestAnnotationIntention;
import org.intellij.plugins.junit4.intentions.ExpectExceptionIntention;
import org.intellij.plugins.junit4.intentions.RemoveTestAnnotationIntention;
import org.intellij.plugins.junit4.listeners.RenameListenerProvider;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;

/**
 * Project component.
 *
 * @author Justin Tomich
 */
public class JUnitProjectComponent
        implements ProjectComponent, Configurable, JDOMExternalizable
{
    private final Logger log = Logger.getLogger("CONSOLE-WARN");
    private final Configuration config = new Configuration();

    private final Project project;
    private final PsiManager psiManager;
    private ConfigurationPanel form;
    private JavaFileFactory fileFactory;

    // todo prefix and suffix should come from config
    private ClassNameResolver resolver;


    public static JUnitProjectComponent getProjectComponent(AnActionEvent event)
    {
        Project project = DataKeys.PROJECT.getData(event.getDataContext());
        return getProjectComponent(project);
    }


    public static JUnitProjectComponent getProjectComponent(Project p)
    {
        JUnitProjectComponent component = p.getComponent(JUnitProjectComponent.class);
        if (component == null)
        {
            throw new RuntimeException("null JUnitProjectComponent!");
        }
        return component;
    }


    public JUnitProjectComponent(Project project)
    {
        this.project = project;
        psiManager = PsiManager.getInstance(project);
        log.warn(this + " instantiated!");
    }


    public void projectOpened()
    {
        config.setDefaultsIfNotConfigured();
        resolver = new ClassNameResolver(config);
        fileFactory = new JavaFileFactory(psiManager, resolver);

        RefactoringListenerManager refM = RefactoringListenerManager.getInstance(project);
        refM.addListenerProvider(new RenameListenerProvider(fileFactory, resolver));

        // register intention
        final IntentionManager intM = IntentionManager.getInstance();
//        intM.addAction(new ExpectExceptionIntention());
        intM.addAction(new AddTestAnnotationIntention());
        intM.addAction(new RemoveTestAnnotationIntention());
    }

    public JavaFileFactory fileFactory()
    {
        return fileFactory;
    }


    public void projectClosed()
    {
    }


    @NonNls
    @NotNull
    public String getComponentName()
    {
        return "JUnit4Plugin.JUnitProjectComponent";
    }


    public void initComponent()
    {
    }


    public void disposeComponent()
    {
    }


    @Nls
    public String getDisplayName()
    {
        return "Junit Assist";
    }


    public Icon getIcon()
    {
        // todo - get icon
        return null;
    }


    @Nullable
    @NonNls
    public String getHelpTopic()
    {
        // todo - get help setup
        return null;
    }


    public JComponent createComponent()
    {
        if (form == null)
        {
            form = new ConfigurationPanel();
        }
        return form;
    }


    public boolean isModified()
    {
        return form != null && form.isModified(config);
    }


    public void apply() throws ConfigurationException
    {
        if (form != null)
        {
            // Get data from form to component
            form.setTo(config);
            config.setDefaultsIfNotConfigured();
            resolver = new ClassNameResolver(config);
            fileFactory = new JavaFileFactory(psiManager, resolver);
        }
    }


    public void reset()
    {
        if (form != null)
        {
            // Reset form data from component
            form.readFrom(config);
        }
    }


    public void disposeUIResources()
    {
        form = null;
    }


    public void readExternal(Element element) throws InvalidDataException
    {
        DefaultJDOMExternalizer.readExternal(config, element);
    }


    public void writeExternal(Element element) throws WriteExternalException
    {
        DefaultJDOMExternalizer.writeExternal(config, element);
    }


    public String toString()
    {
        return "JUnitProjectComponent{" +
                "project=" + project +
                ", psiManager=" + psiManager +
                ", fileFactory=" + fileFactory +
                ", resolver=" + resolver +
                '}';
    }
}
